package com.cong.security.core.social.app;

import java.util.HashSet;
import java.util.Set;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.social.connect.UsersConnectionRepository;
import org.springframework.social.security.SocialUserDetailsService;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class OpenIdAuthenticationProvider implements AuthenticationProvider {
	private SocialUserDetailsService userDetailsService;
	// UserConnection表
	private UsersConnectionRepository usersConnectionRepository;
	@Override
	public Authentication authenticate(Authentication authentication) throws AuthenticationException {
		OpenIdAuthenticationToken openIdAuthenticationToken = (OpenIdAuthenticationToken) authentication;
		Set<String> providerUserIds = new HashSet<>();
		// 获取到用户登陆的openId
		providerUserIds.add((String) authentication.getPrincipal());
		// 用户选择的登录方式
		String providerId = openIdAuthenticationToken.getProviderId();
		log.info("用户[{}]登录方式为[{}]", providerUserIds, providerId);
		// 数据库中是否有记录
		Set<String> userIds = usersConnectionRepository.findUserIdsConnectedTo(providerId, providerUserIds);
		log.info("匹配到的用户信息ID为[{}]", userIds);// 理论上只能拿到一个,一个系统账号可以绑定多个社交账号,但是一个社交账号只能绑定一个系统账号
		if (CollectionUtils.isEmpty(userIds) || userIds.size() != 1) {
			throw new InternalAuthenticationServiceException("该账户尚未绑定至系统账号,提示用户执行绑定操作");
		}
		// 根据社交账号查出来的用户的唯一标识
		String userId = userIds.iterator().next();
		UserDetails user = userDetailsService.loadUserByUserId(userId);
		if (user == null) {
			// 绑定的用户标识无法从本系统中查询到用户信息,主动抛出异常
			throw new InternalAuthenticationServiceException("无法获取用户信息");
		}
		// 构建用户以及用户权限信息
		OpenIdAuthenticationToken openIdAuthenticationResult = new OpenIdAuthenticationToken(user,
				user.getAuthorities());
		// UserDetails或者SocialDetails用户信息
		openIdAuthenticationResult.setDetails(openIdAuthenticationToken.getDetails());
		// 返回封装的token信息,上层进行JWT-token生成
		return openIdAuthenticationResult;
	}

	@Override
	public boolean supports(Class<?> authentication) {
		return OpenIdAuthenticationToken.class.isAssignableFrom(authentication);
	}

	public void setUserDetailsService(SocialUserDetailsService userDetailsService) {
		this.userDetailsService = userDetailsService;
	}

	public void setUsersConnectionRepository(UsersConnectionRepository usersConnectionRepository) {
		this.usersConnectionRepository = usersConnectionRepository;
	}
}
